﻿/*
____
 L|ypps Web controls for ASP.NET

Copyright (c) 2009 Alessandro Zifiglio, http://www.Typps.com
EMail: alessandro@Typps.com

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
namespace Typps
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Text;
    using System.Web;

    #region Enumerations

    public enum BrowserIdentifier
    {
        NotSet,
        Firefox,
        InternetExplorer,
        Opera,
        Safari,
        Chrome,
        AppleWebKit,
        Gecko,
        Netscape
    }

    internal enum VersionLocation
    {
        Begining,
        MiddleSlash,
        MiddleSpaceAndColon,
        EndSlash
    }

    #endregion Enumerations

    public class UserAgent
    {
        #region Fields

        BrowserIdentifier browserNameValue = BrowserIdentifier.NotSet;
        double browserVersionValue;

        #endregion Fields

        #region Constructors

        public UserAgent()
        {
            Initialize();
        }

        #endregion Constructors

        #region Properties

        public BrowserIdentifier BrowserName
        {
            get { return browserNameValue; }
            set { browserNameValue = value; }
        }

        public double BrowserVersion
        {
            get { return browserVersionValue; }
            set { browserVersionValue = value; }
        }

        #endregion Properties

        #region Methods

        /*
         Version numbers are usually seperated by one or more dots('.')
         * The extra dots usually represent beta build numbers and so on which we are not interested in.
         * We only want the number up to the first dot. This denotes the version number which we are looking
         * for. Our method below also checks for
         */
        public double ConvertVersionToDouble(string versionNumber)
        {
            NumberFormatInfo nFI = null;
            double returnValue;
            CultureInfo ci = CultureInfo.InstalledUICulture;
            nFI = (NumberFormatInfo)ci.NumberFormat.Clone();
            nFI.NumberDecimalSeparator = ".";
            nFI.NumberGroupSeparator = ",";
            if (versionNumber.IndexOf('.') != -1)
            {
                string[] array1 = versionNumber.Split('.');
                versionNumber = array1[0].ToString() + '.' + array1[1].ToString();
            }
            bool success = double.TryParse(versionNumber, NumberStyles.Any, nFI, out returnValue);
            if (!success) return 0.0;
            return returnValue;
        }

        public void Initialize()
        {
            if (HttpContext.Current == null ||
                HttpContext.Current.Request.UserAgent == null)
                return;//designmode
            string userAgent = HttpContext.Current.Request.UserAgent.ToLower(CultureInfo.InvariantCulture);
            // Sample UserAgent String : Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.1) Gecko/20060111 Firefox/1.5.0.1
            if (userAgent.IndexOf("firefox/") != -1)
            {
                BrowserName = BrowserIdentifier.Firefox;
                BrowserVersion = ExtractVersion(userAgent, VersionLocation.EndSlash, "firefox/");
                return;
            }
            // Sample UserAgent String : Mozilla/4.0 (compatible; MSIE 6.0.6.9; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50215)
            if (userAgent.IndexOf("msie") != -1 &&
                userAgent.IndexOf("opera") == -1)
            {
                BrowserName = BrowserIdentifier.InternetExplorer;
                BrowserVersion = ExtractVersion(userAgent, VersionLocation.MiddleSpaceAndColon, "msie ");
                return;
            }

            // Sample UserAgent String : Opera/9.0 (Windows NT 5.1; U; en)
            if (userAgent.IndexOf("opera/") != -1)
            {
                BrowserName = BrowserIdentifier.Opera;
                BrowserVersion = ExtractVersion(userAgent, VersionLocation.MiddleSlash, "opera/");
                return;
            } // Sample UserAgent String : Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 8.51
            else if (userAgent.IndexOf("opera") != -1)
            {
                BrowserName = BrowserIdentifier.Opera;
                BrowserVersion = ExtractVersion(userAgent, VersionLocation.EndSlash, "opera ");
                return;
            }
            //"mozilla/5.0 (windows; u; windows nt 6.0; en-us) applewebkit/525.19 (khtml, like gecko) chrome/1.0.154.48 safari/525.19"
            if (userAgent.IndexOf("chrome") != -1)
            {
                BrowserName = BrowserIdentifier.Chrome;
                BrowserVersion = ExtractVersion(userAgent, VersionLocation.MiddleSlash, "chrome/");
                return;
            }
            // must support Safari 2.0.1 and above because they support the DOMParser
            // Sample UserAgent String : Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en) AppleWebKit/417.2 (KHTML, like Gecko) Safari/417.1
            if (userAgent.IndexOf("safari") != -1)
            {
                BrowserName = BrowserIdentifier.Safari;
                BrowserVersion = ExtractVersion(userAgent, VersionLocation.MiddleSlash, "version/");
                return;
            }
            //string userAgent = "Mozilla/5.0 (PC; U; Intel; Windows; en) AppleWebKit/420+ (KHTML, like Gecko)".ToLower();
            // Sample UserAgent String : 1. Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.5 (KHTML, like Gecko) Safari/125.11
            // Sample UserAgent String : 2. Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/85.8.2 (KHTML, like Gecko) RealPlayer
            if (userAgent.IndexOf("applewebkit/") != -1)
            {
                BrowserName = BrowserIdentifier.AppleWebKit;
                BrowserVersion = ExtractVersion(userAgent.Replace("+", ""), VersionLocation.MiddleSlash, "applewebkit/");
                return;
            }
        }

        public virtual bool IsUpLevel()
        {
            bool uplevel = false;
            switch (BrowserName)
            {
                case BrowserIdentifier.InternetExplorer:
                    uplevel = (BrowserVersion >= 6);
                    break;
                case BrowserIdentifier.Firefox:
                    uplevel = (BrowserVersion >= 2);
                    break;
                case BrowserIdentifier.Opera:
                    uplevel = (BrowserVersion >= 9);
                    break;
                case BrowserIdentifier.Chrome:
                    uplevel = (BrowserVersion >= 1);
                    break;
                case BrowserIdentifier.Safari:
                    uplevel = (BrowserVersion >= 3);
                    break;
                case BrowserIdentifier.AppleWebKit:
                    uplevel = (BrowserVersion >= 125);
                    break;
            }
            return uplevel;
        }

        private double ExtractVersion(string userAgent, VersionLocation location, string browserName)
        {
            string currentVersion = "0";
            if (location == VersionLocation.MiddleSlash)// there is a forward slash and an empty space after version number
            {
                currentVersion = userAgent.Substring((userAgent.IndexOf(browserName) + browserName.Length), userAgent.IndexOf(' ', userAgent.IndexOf(browserName) + browserName.Length) - (userAgent.IndexOf(browserName) + browserName.Length));
            }
            else if (location == VersionLocation.MiddleSpaceAndColon)// IE is known to have the version number prefixed with a semicolon, which we dont want :-)
            {
                currentVersion = userAgent.Substring((userAgent.IndexOf(browserName) + browserName.Length), userAgent.IndexOf(' ', userAgent.IndexOf(browserName) + browserName.Length) - (userAgent.IndexOf(browserName) + browserName.Length + 1)); // + 1 because of the semicolon, which we want to exclude
            }
            else if (location == VersionLocation.EndSlash)
            {
                currentVersion = userAgent.Substring(userAgent.IndexOf(browserName) + browserName.Length, (userAgent.Length - (userAgent.IndexOf(browserName) + browserName.Length)));
            }// following one is never used. I wrote it originally for opera but is useless now since MiddleSlash works nicely.
            else if (location == VersionLocation.Begining)
            {
                string[] text1 = userAgent.Split(' ');
                string[] text2 = text1[0].Split('/');
                currentVersion = text2[1];
            }
            currentVersion = currentVersion.Trim();
            if (currentVersion.IndexOf(' ') != -1)
                currentVersion = currentVersion.Split(' ')[0];
            return ConvertVersionToDouble(currentVersion);
        }

        #endregion Methods
    }
}